<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN">
@extends('layouts.master3')
@section('content')
<div class="row">
<div class="col-md-1"></div>
<div class="col-md-10">
<h1>qllanguage-alpha介绍</h1><p>
qll是一个模仿nasa考试的程序员训练语言，它非常的简单，却又是图灵机完备的，可以支持循环，分支，判断，输入(后续增加)，输出，多线程(后续增加)等基本功能。<p>
qll的数据存储非常的简单，由一个基本的整型(int32范围)栈构成，所有元素先进后出。<p>
qll的代码由下面的指令列表构成，每个指令有一个独特的含义。当遇到无法识别的指令则异常退出。<p>

在qll的程序运行阶段，程序的执行指针指向qll代码的第一个字符(codes[0],代码字符串的第1位)，在执行完当前指令后，执行指针向前移动一位(codes[1],代码字符串的第2位),并执行下一个指令。当执行指针遇到指令'e'程序结束。

<h2>指令和例子</h2>
<table border="2">
	<tr><th>指令</th><th>描述</th><th><font color="red">举例(可以把例子中的代码放入本页面下方的在线IDE中执行),很重要,实践出真知</font></th></tr>
    <tr><td>' '</td><td>无意义的填充字符</td><td>无</td>
		<tr><td>'p'</td><td>将栈首元素取出并以整数形式输出,类似<font color="red">p</font>rintf</td><td>代码:"12345pppppe" 输出:"54321"</td>
	<tr><td>'P'</td><td>将栈首元素取出并以ASCII码输出</td><td>代码:"99*Pe" 输出:"Q"</td>
	<tr><td>'0'-'9'</td><td>将整数0-9放入栈</td><td>无</td>
    <tr><td>'+'</td><td>取出栈顶的2个元素,将它们的和放回栈</td><td>代码:"123++pe" 输出:"6"</td>
    <tr><td>'-'</td><td>取出栈顶的2个元素,将它们的差放回栈</td><td>代码:"54-pe" 输出:"1"</td>
    <tr><td>'*'</td><td>取出栈顶的2个元素,将它们的乘积放回栈</td><td>代码:"234**pe" 输出:"24"</td>
    <tr><td>'/'</td><td>取出栈顶的2个元素,将它们的商放回栈</td><td>代码:"92/pe" 输出:"4"</td>
		<tr><td>'m'</td><td>取出栈顶元素x,将程序的执行指针向前<font color="red">m</font>ove x位</td><td>代码:"34m2*pe3*pe" 输出:"9"</td>
			<tr><td>'g'</td><td>取出栈顶元素a,将程序的执行指针挪动到第a位,类似c的<font color="red">g</font>oto</td><td>代码:"1yp48*P1+1g" 输出:"1,2,3...直到死循环异常"</td>
				<tr><td>'i'</td><td>取出栈顶元素a,再取出栈顶元素b,<br>如果b等于0,那么将程序的执行指针向前挪动a位<br>类似<font color="red">i</font>f</td><td>代码:"1yp48*P1+y9-2i1ge" 输出:"1 2 3 4 5 6 7 8 ",请仔细和上一行的例子做对比</td>
					<tr><td>'d'</td><td>将栈顶元素弹出,<font color="red">d</font>rop</td><td>代码:"12345dpe" 输出:"4"</td>
    <tr><td>'y'</td><td>复制栈顶元素,并放入栈</td><td>代码:"1yyyppppe" 输出:"1111"</td>
		<tr><td>'e'</td><td>当读到这个字符,程序结束,<font color="red">e</font>nd</td><td>无</td>
</table>
<h2> 在线IDE</h2>
<script type="text/javascript">
var outputString = "";
var output;
var MAX_CYCLES  = 10000;
var OperandStack;
var ProgramCounter;
var Code;
function EmitOutput(txt) {
    outputString += txt;
    output.value = outputString;    
}

function Push(v) {
    if (isNaN(v)) throw "illegal value";
    if (v > 2147483647 || v < -2147483648) throw "整数越界";
    OperandStack.push(v);
}

function Pop() {
    if (OperandStack.length == 0) throw "堆中已经没有任何元素了";
    return OperandStack.pop();
}

var Instructions = {
    ' ': function() {},
    '0': function() { Push(0) },
    '1': function() { Push(1) },
    '2': function() { Push(2) },
    '3': function() { Push(3) },
    '4': function() { Push(4) },
    '5': function() { Push(5) },
    '6': function() { Push(6) },
    '7': function() { Push(7) },
    '8': function() { Push(8) },
    '9': function() { Push(9) },
    '+': function() { Push(Pop()+Pop()) },
    '-': function() { var a = Pop(); var b = Pop(); Push(b-a) },
    '*': function() { Push(Pop()*Pop()) },
    '/': function() { var a = Pop(); var b = Pop(); Push(Math.floor(b/a)) },
    'p': function() { EmitOutput(Pop()) },
    'P': function() { EmitOutput(String.fromCharCode(Pop()&0x7F)) },
    'm': function() { ProgramCounter += Pop() },
    'i': function() { var offset=Pop(); if (Pop() == 0) ProgramCounter += offset },
    'g': function() { ProgramCounter = Pop() },
    'd': function() { Pop(); },
    'y': function() { var a=Pop();Push(a);Push(a);},
    'e': function() { ProgramCounter = Code.length }
}

function Run() {
    output = document.getElementById("output");
    output.value = "";
    outputString = "";
    Code = document.getElementById("code").value;
    var traceOutput = document.getElementById("trace_output");
    var traceBuffer = "";
    
    // init the state
    ProgramCounter = 0;
    OperandStack = [];
    
    // run loop    
    var cycleCounter = 0;
    try {
        while (true) {
            var instruction = Code[ProgramCounter++];
            if (cycleCounter++ > MAX_CYCLES) throw "循环太多次了,代码是不是死循环了呢";
			if(Instructions[instruction]==null)throw '无法识别指令 '+instruction;
            Instructions[instruction]();
            if (instruction != ' ') {
                traceBuffer += '当前指令:'+instruction+' 栈内元素:['+OperandStack+']\n';
            }
			if(instruction == 'e')break;
            if (ProgramCounter <0 || ProgramCounter >= Code.length) throw '程序的执行指针超过了代码的边界';
        }
    } catch (e) {
        EmitOutput("错误: "+e);
    }
	 traceOutput.value = traceBuffer;
}

function TraceBoxChanged() {
    var textarea = document.getElementById('trace_output');
    textarea.style.display = 'block';    
}
</script>
<form id="vm_form" autocomplete="off"> 
  代码编辑框:<br>
  <textarea id="code" name="code_text" type="text" class="textbox" rows="4" cols="80"></textarea><br>
  <input type="BUTTON" name="run" value="执行" onclick="Run()">
  输出控制台:<br>
  <textarea id="output" name="output_text" type="text" class="textbox" rows="4" cols="80"></textarea><br>
  堆信息:<br>
  <textarea id="trace_output" name="trace_output_text" type="text" class="textbox" rows="20" cols="80"></textarea><br>
</form> 
</div>
<div class="col-md-1"></div>
</div>
@stop

